package com.javasea.netty.har.common.endec;

import com.google.protobuf.MessageLite;
import com.javasea.netty.har.common.constant.CmdConstant;
import com.javasea.netty.har.common.entity.proto.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * 参考ProtobufVarint32LengthFieldPrepender 和 ProtobufEncoder
 * CustomProtobufEncoder序列化传入的protobuf类型，
 * 并且为它创建了一个4个字节的包头，内容格式如下
 * body长度（low）----> body长度（high）----> 保留字节 ----> 类型
 */
@Sharable
public class CustomProtobufEncoder extends MessageToByteEncoder<MessageLite> {

    @Override
    protected void encode(
            ChannelHandlerContext ctx, MessageLite msg, ByteBuf buffer) throws Exception {
        byte[] body = msg.toByteArray();
        byte[] header = encodeHeader(msg, (short)body.length);

        // 包头标识，避免出现分包或者沾包现象
        buffer.writeInt(CmdConstant.HEADER_FLAG);
        // 包头内容
        buffer.writeBytes(header);
        // 消息体
        buffer.writeBytes(body);

        return;
    }

    private byte[] encodeHeader(MessageLite msg, short bodyLength) {
        byte messageType = 0x0f;

        if (msg instanceof CmdBatchProto.CmdBatch) {
            messageType = CmdConstant.Cmd.CMD_BATCH;
        } else if (msg instanceof CommandProto.Command) {
            messageType = CmdConstant.Cmd.COMMAND;
        } else if (msg instanceof PrintStateMsgProto.PrintStateMsgNotice) {
            messageType = CmdConstant.Cmd.PRINT_STATE_MSG_NOTICE;
        } else if (msg instanceof PrintStateMsgProto.PrintStateMsgConfirm) {
            messageType = CmdConstant.Cmd.PRINT_STATE_MSG_CONFIRM;
        } else if (msg instanceof HeartProto.Heart) {
            messageType = CmdConstant.Cmd.HEART;
        } else if (msg instanceof ResultProto.Result) {
            messageType = CmdConstant.Cmd.RESULT;
        } else if (msg instanceof NioClientProto.NioClient) {
            messageType = CmdConstant.Cmd.NIO_CLIENT;
        }

        byte[] header = new byte[4];
        header[0] = (byte) (bodyLength & 0xff);
        header[1] = (byte) ((bodyLength >> 8) & 0xff);
        // 保留字段
        header[2] = 0;
        header[3] = messageType;

        return header;

    }
}

